Python ORM๊ณผ Raw SQL ๊ฐ์ ์ฑ๋ฅ ํธ๋ ์ด๋ ์คํ๋ฅผ ์ดํด๋ณด๊ณ , ํ๋ก์ ํธ์ ์ ํฉํ ์ ๊ทผ ๋ฐฉ์์ ์ ํํ๊ธฐ ์ํ ์ค์ฉ์ ์ธ ์์์ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํฉ๋๋ค.
Python ORM vs. Raw SQL: ์ฑ๋ฅ ํธ๋ ์ด๋ ์คํ ๋ฐ ์ ํ ์๊ธฐ
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ ์์ฉํ๋ Python ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋, Object-Relational Mapper(ORM)๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ Raw SQL ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๊ทผ๋ณธ์ ์ธ ์ ํ์ ์ง๋ฉดํ๊ฒ ๋ฉ๋๋ค. ๋ ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์ ๋ชจ๋ ํนํ ์ฑ๋ฅ๊ณผ ๊ด๋ จํ์ฌ ์ฅ๋จ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด ๊ธ์์๋ Python ORM๊ณผ Raw SQL ๊ฐ์ ์ฑ๋ฅ ํธ๋ ์ด๋ ์คํ๋ฅผ ์์ธํ ์ดํด๋ณด๊ณ , ํ๋ก์ ํธ์ ๋ํ ์ ๋ณด์ ์ ๊ฐํ ๊ฒฐ์ ์ ๋ด๋ฆฌ๋ ๋ฐ ๋์์ด ๋๋ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํฉ๋๋ค.
ORM๊ณผ Raw SQL์ด๋ ๋ฌด์์ธ๊ฐ์?
Object-Relational Mapper (ORM)
ORM์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํธํ๋์ง ์๋ ์ ํ ์์คํ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ์ ์ ๋๋ค. ๋ณธ์ง์ ์ผ๋ก SQL ์ฟผ๋ฆฌ๋ฅผ ์ง์ ์์ฑํ๋ ๋์ Python ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ ์์ฉํ ์ ์๋ ์ถ์ํ ๊ณ์ธต์ ์ ๊ณตํฉ๋๋ค. ์ธ๊ธฐ ์๋ Python ORM์๋ SQLAlchemy, Django ORM ๋ฐ Peewee๊ฐ ์์ต๋๋ค.
ORM์ ์ฅ์ :
- ์์ฐ์ฑ ํฅ์: ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ์ ๋จ์ํํ์ฌ ์์ฑํด์ผ ํ๋ ์์ฉ๊ตฌ ์ฝ๋์ ์์ ์ค์ ๋๋ค.
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ: ORM์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ชจ๋ธ์ Python ํด๋์ค๋ก ์ ์ํ์ฌ ์ฝ๋ ์ฌ์ฌ์ฉ ๋ฐ ์ ์ง ๊ด๋ฆฌ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ถ์ํ: ORM์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ถ์ํํ์ฌ ์ต์ํ์ ์ฝ๋ ๋ณ๊ฒฝ์ผ๋ก ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ (์: PostgreSQL, MySQL, SQLite) ๊ฐ์ ์ ํํ ์ ์์ต๋๋ค.
- ๋ณด์: ๋ง์ ORM์ SQL ์ฃผ์ ์ทจ์ฝ์ฑ์ ๋ํ ๋ด์ฅ๋ ๋ณดํธ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
Raw SQL
Raw SQL์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ ์์ฉํ๊ธฐ ์ํด Python ์ฝ๋์์ SQL ์ฟผ๋ฆฌ๋ฅผ ์ง์ ์์ฑํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ์คํ๋๋ ์ฟผ๋ฆฌ ๋ฐ ๊ฒ์๋ ๋ฐ์ดํฐ๋ฅผ ์๋ฒฝํ๊ฒ ์ ์ดํ ์ ์์ต๋๋ค.
Raw SQL์ ์ฅ์ :
- ์ฑ๋ฅ ์ต์ ํ: Raw SQL์ ์ฌ์ฉํ๋ฉด ํนํ ๋ณต์กํ ์์ ์ ๊ฒฝ์ฐ ์ต์ ์ ์ฑ๋ฅ์ ์ํด ์ฟผ๋ฆฌ๋ฅผ ๋ฏธ์ธ ์กฐ์ ํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ๊ธฐ๋ฅ: ORM์์ ์ง์ํ์ง ์์ ์ ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ๊ธฐ๋ฅ ๋ฐ ์ต์ ํ๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค.
- ์ง์ ์ ์ด: ์์ฑ๋ SQL์ ์๋ฒฝํ๊ฒ ์ ์ดํ์ฌ ์ ํํ ์ฟผ๋ฆฌ ์คํ์ ํ์ฉํฉ๋๋ค.
์ฑ๋ฅ ํธ๋ ์ด๋ ์คํ
ORM๊ณผ Raw SQL์ ์ฑ๋ฅ์ ์ฌ์ฉ ์ฌ๋ก์ ๋ฐ๋ผ ํฌ๊ฒ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค. ํจ์จ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ค๋ฉด ์ด๋ฌํ ํธ๋ ์ด๋ ์คํ๋ฅผ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ฟผ๋ฆฌ ๋ณต์ก์ฑ
๋จ์ ์ฟผ๋ฆฌ: ๋จ์ CRUD(์์ฑ, ์ฝ๊ธฐ, ์ ๋ฐ์ดํธ, ์ญ์ ) ์์ ์ ๊ฒฝ์ฐ ORM์ ์ข ์ข Raw SQL๊ณผ ์ ์ฌํ ์ฑ๋ฅ์ ๋ณด์ ๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ ORM์ ์ค๋ฒํค๋๋ ์ต์์ ๋๋ค.
๋ณต์กํ ์ฟผ๋ฆฌ: ์ฟผ๋ฆฌ ๋ณต์ก์ฑ์ด ์ฆ๊ฐํจ์ ๋ฐ๋ผ Raw SQL์ ์ผ๋ฐ์ ์ผ๋ก ORM๋ณด๋ค ์ฑ๋ฅ์ด ๋ฐ์ด๋ฉ๋๋ค. ORM์ ๋ณต์กํ ์์ ์ ๋ํด ๋นํจ์จ์ ์ธ SQL ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ์ฌ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์ด๋ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ณต์กํ ํํฐ๋ง ๋ฐ ์ง๊ณ๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ํ ์ด๋ธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํด์ผ ํ๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ณด์ญ์์ค. ์๋ชป ๊ตฌ์ฑ๋ ORM ์ฟผ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฌ๋ฌ ์๋ณต์ ์ํํ์ฌ ํ์ ์ด์์ผ๋ก ๋ง์ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ ์ ์๋ ๋ฐ๋ฉด, ์๋์ผ๋ก ์ต์ ํ๋ Raw SQL ์ฟผ๋ฆฌ๋ ๋ ์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ์ผ๋ก ๋์ผํ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ
์ฟผ๋ฆฌ ์: ORM์ ๋๋๋ก ๊ฒ๋ณด๊ธฐ์๋ ๊ฐ๋จํ ์์ ์ ๋ํด ๋ง์ ์์ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ฅผ N+1 ๋ฌธ์ ๋ผ๊ณ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๊ฐ์ฒด ๋ชฉ๋ก์ ๊ฒ์ํ ๋ค์ ๋ชฉ๋ก์ ๊ฐ ํญ๋ชฉ์ ๋ํด ๊ด๋ จ ๊ฐ์ฒด์ ์ก์ธ์คํ๋ ๊ฒฝ์ฐ ORM์ N+1๊ฐ์ ์ฟผ๋ฆฌ(๋ชฉ๋ก์ ๊ฒ์ํ๊ธฐ ์ํ ํ๋์ ์ฟผ๋ฆฌ ๋ฐ ๊ด๋ จ ๊ฐ์ฒด๋ฅผ ๊ฒ์ํ๊ธฐ ์ํ N๊ฐ์ ์ถ๊ฐ ์ฟผ๋ฆฌ)๋ฅผ ์คํํ ์ ์์ต๋๋ค. Raw SQL์ ์ฌ์ฉํ๋ฉด ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๊ธฐ ์ํด ๋จ์ผ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ์ฌ N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์ฟผ๋ฆฌ ์ต์ ํ: Raw SQL์ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ ์ต์ ํ๋ฅผ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์์ต๋๋ค. ์ธ๋ฑ์ค, ์ฟผ๋ฆฌ ํํธ ๋ฐ ์ ์ฅ ํ๋ก์์ ์ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ORM์ ํญ์ ์ด๋ฌํ ๊ณ ๊ธ ์ต์ ํ ๊ธฐ์ ์ ๋ํ ์ก์ธ์ค๋ฅผ ์ ๊ณตํ์ง ๋ชปํ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ๊ฒ์
๋ฐ์ดํฐ ํ์ด๋๋ ์ด์ : ORM์ ๊ฒ์๋ ๋ฐ์ดํฐ๋ฅผ Python ๊ฐ์ฒด๋ก ํ์ด๋๋ ์ด์ ํ๋ ์ถ๊ฐ ๋จ๊ณ๋ฅผ ํฌํจํฉ๋๋ค. ์ด ํ๋ก์ธ์ค๋ ํนํ ๋์ฉ๋ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ค๋ฒํค๋๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค. Raw SQL์ ์ฌ์ฉํ๋ฉด ํํ ๋๋ ์ฌ์ ๊ณผ ๊ฐ์ ๋ณด๋ค ๊ฐ๋ฒผ์ด ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ์ฌ ๋ฐ์ดํฐ ํ์ด๋๋ ์ด์ ์ ์ค๋ฒํค๋๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
์บ์ฑ
ORM ์บ์ฑ: ๋ง์ ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ถํ๋ฅผ ์ค์ด๊ธฐ ์ํด ์บ์ฑ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ ์บ์ฑ์ ์ ์คํ๊ฒ ๊ด๋ฆฌํ์ง ์์ผ๋ฉด ๋ณต์ก์ฑ๊ณผ ์ ์ฌ์ ์ธ ๋ถ์ผ์น๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, SQLAlchemy๋ ๊ตฌ์ฑํ ์ ์๋ ๋ค์ํ ์์ค์ ์บ์ฑ์ ์ ๊ณตํฉ๋๋ค. ์บ์ฑ์ด ์๋ชป ์ค์ ๋ ๊ฒฝ์ฐ ์ค๋๋ ๋ฐ์ดํฐ๊ฐ ๋ฐํ๋ ์ ์์ต๋๋ค.
Raw SQL ์บ์ฑ: Raw SQL๋ก ์บ์ฑ ์ ๋ต์ ๊ตฌํํ ์ ์์ง๋ง ๋ ๋ง์ ์๋ ์์ ์ด ํ์ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก Redis ๋๋ Memcached์ ๊ฐ์ ์ธ๋ถ ์บ์ฑ ๊ณ์ธต์ ํ์ฉํด์ผ ํฉ๋๋ค.
์ค์ฉ์ ์ธ ์
SQLAlchemy์ Raw SQL์ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ ํธ๋ ์ด๋ ์คํ๋ฅผ ์ค์ฉ์ ์ธ ์์๋ก ์ค๋ช ํด ๋ณด๊ฒ ์ต๋๋ค.
์์ 1: ๋จ์ ์ฟผ๋ฆฌ
ORM (SQLAlchemy):
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# Create some users
user1 = User(name='Alice', age=30)
user2 = User(name='Bob', age=25)
session.add_all([user1, user2])
session.commit()
# Query for a user by name
user = session.query(User).filter_by(name='Alice').first()
print(f"ORM: User found: {user.name}, {user.age}")
Raw SQL:
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
''')
# Insert some users
cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Alice', 30))
cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Bob', 25))
conn.commit()
# Query for a user by name
cursor.execute("SELECT name, age FROM users WHERE name = ?", ('Alice',))
user = cursor.fetchone()
print(f"Raw SQL: User found: {user[0]}, {user[1]}")
conn.close()
์ด ๊ฐ๋จํ ์์์์๋ ORM๊ณผ Raw SQL ๊ฐ์ ์ฑ๋ฅ ์ฐจ์ด๊ฐ ๋ฏธ๋ฏธํฉ๋๋ค.
์์ 2: ๋ณต์กํ ์ฟผ๋ฆฌ
์ฌ์ฉ์์ ๊ด๋ จ ์ฃผ๋ฌธ์ ๊ฒ์ํด์ผ ํ๋ ๋ ๋ณต์กํ ์๋๋ฆฌ์ค๋ฅผ ๊ณ ๋ คํด ๋ณด๊ฒ ์ต๋๋ค.
ORM (SQLAlchemy):
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
orders = relationship("Order", back_populates="user")
class Order(Base):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
product = Column(String)
user = relationship("User", back_populates="orders")
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# Create some users and orders
user1 = User(name='Alice', age=30)
user2 = User(name='Bob', age=25)
order1 = Order(user=user1, product='Laptop')
order2 = Order(user=user1, product='Mouse')
order3 = Order(user=user2, product='Keyboard')
session.add_all([user1, user2, order1, order2, order3])
session.commit()
# Query for users and their orders
users = session.query(User).all()
for user in users:
print(f"ORM: User: {user.name}, Orders: {[order.product for order in user.orders]}")
#Demonstrates the N+1 problem. Without eager loading, a query is executed for each user's orders.
Raw SQL:
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
''')
cursor.execute('''
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
product TEXT,
FOREIGN KEY (user_id) REFERENCES users(id)
)
''')
# Insert some users and orders
cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Alice', 30))
cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Bob', 25))
user_id_alice = cursor.lastrowid # Get Alice's ID
cursor.execute("INSERT INTO orders (user_id, product) VALUES (?, ?)", (user_id_alice, 'Laptop'))
cursor.execute("INSERT INTO orders (user_id, product) VALUES (?, ?)", (user_id_alice, 'Mouse'))
user_id_bob = cursor.execute("SELECT id FROM users WHERE name = 'Bob'").fetchone()[0]
cursor.execute("INSERT INTO orders (user_id, product) VALUES (?, ?)", (user_id_bob, 'Keyboard'))
conn.commit()
# Query for users and their orders using JOIN
cursor.execute("""
SELECT users.name, orders.product
FROM users
LEFT JOIN orders ON users.id = orders.user_id
""")
results = cursor.fetchall()
user_orders = {}
for name, product in results:
if name not in user_orders:
user_orders[name] = []
if product: #Product can be null
user_orders[name].append(product)
for user, orders in user_orders.items():
print(f"Raw SQL: User: {user}, Orders: {orders}")
conn.close()
์ด ์์์์ Raw SQL์ ํนํ ORM์ด ์ฌ๋ฌ ์ฟผ๋ฆฌ ๋๋ ๋นํจ์จ์ ์ธ JOIN ์์ ์ ์์ฑํ๋ ๊ฒฝ์ฐ์ ์๋นํ ๋ ๋น ๋ฅผ ์ ์์ต๋๋ค. Raw SQL ๋ฒ์ ์ JOIN์ ์ฌ์ฉํ์ฌ ๋จ์ผ ์ฟผ๋ฆฌ์์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ์ฌ N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
ORM์ ์ ํํด์ผ ํ๋ ๊ฒฝ์ฐ
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ ORM์ด ์ข์ต๋๋ค:
- ๋น ๋ฅธ ๊ฐ๋ฐ์ด ์ฐ์ ์์์ธ ๊ฒฝ์ฐ. ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ์ ๋จ์ํํ์ฌ ๊ฐ๋ฐ ํ๋ก์ธ์ค๋ฅผ ๊ฐ์ํํฉ๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฃผ๋ก CRUD ์์ ์ ์ํํ๋ ๊ฒฝ์ฐ. ORM์ ๊ฐ๋จํ ์์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ถ์ํ๊ฐ ์ค์ํ ๊ฒฝ์ฐ. ORM์ ์ฌ์ฉํ๋ฉด ์ต์ํ์ ์ฝ๋ ๋ณ๊ฒฝ์ผ๋ก ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ ๊ฐ์ ์ ํํ ์ ์์ต๋๋ค.
- ๋ณด์์ด ์ค์ํ ๊ฒฝ์ฐ. ORM์ SQL ์ฃผ์ ์ทจ์ฝ์ ์ ๋ํ ๋ด์ฅ๋ ๋ณดํธ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ํ์ SQL ์ ๋ฌธ ์ง์์ด ์ ํ์ ์ธ ๊ฒฝ์ฐ. ORM์ SQL์ ๋ณต์ก์ฑ์ ์ถ์ํํ์ฌ ๊ฐ๋ฐ์๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ๋ ์ฝ๊ฒ ํ ์ ์๋๋ก ํฉ๋๋ค.
Raw SQL์ ์ ํํด์ผ ํ๋ ๊ฒฝ์ฐ
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ Raw SQL์ด ์ข์ต๋๋ค:
- ์ฑ๋ฅ์ด ์ค์ํ ๊ฒฝ์ฐ. Raw SQL์ ์ฌ์ฉํ๋ฉด ์ต์ ์ ์ฑ๋ฅ์ ์ํด ์ฟผ๋ฆฌ๋ฅผ ๋ฏธ์ธ ์กฐ์ ํ ์ ์์ต๋๋ค.
- ๋ณต์กํ ์ฟผ๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ. Raw SQL์ ORM์ด ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ์ง ๋ชปํ ์ ์๋ ๋ณต์กํ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ๊ธฐ๋ฅ์ด ํ์ํ ๊ฒฝ์ฐ. Raw SQL์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ๊ธฐ๋ฅ ๋ฐ ์ต์ ํ๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค.
- ์์ฑ๋ SQL์ ์๋ฒฝํ๊ฒ ์ ์ดํด์ผ ํ๋ ๊ฒฝ์ฐ. Raw SQL์ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ ์คํ์ ์์ ํ ์ ์ดํ ์ ์์ต๋๋ค.
- ๋ ๊ฑฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ ๋ณต์กํ ์คํค๋ง๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ. ORM์ ๋ชจ๋ ๋ ๊ฑฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ ์คํค๋ง์ ์ ํฉํ์ง ์์ ์ ์์ต๋๋ค.
ํ์ด๋ธ๋ฆฌ๋ ์ ๊ทผ ๋ฐฉ์
๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ์ด๋ธ๋ฆฌ๋ ์ ๊ทผ ๋ฐฉ์์ด ์ต์์ ์๋ฃจ์ ์ผ ์ ์์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ ์์ฉ์ ๋๋ถ๋ถ์ ORM์ ์ฌ์ฉํ๊ณ ์ต์ ํ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ๊ธฐ๋ฅ์ด ํ์ํ ํน์ ์์ ์ Raw SQL์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ORM๊ณผ Raw SQL์ ์ด์ ์ ๋ชจ๋ ํ์ฉํ ์ ์์ต๋๋ค.
๋ฒค์น๋งํน ๋ฐ ํ๋กํ์ผ๋ง
ํน์ ์ฌ์ฉ ์ฌ๋ก์ ORM๊ณผ Raw SQL ์ค ์ด๋ ๊ฒ์ด ๋ ๋์ ์ฑ๋ฅ์ ๋ณด์ด๋์ง ํ์ธํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ฒค์น๋งํน ๋ฐ ํ๋กํ์ผ๋ง์ ์ํํ๋ ๊ฒ์ ๋๋ค. `timeit` ๋๋ ํน์ ํ๋กํ์ผ๋ง ๋๊ตฌ์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ์ฟผ๋ฆฌ์ ์คํ ์๊ฐ์ ์ธก์ ํ๊ณ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ์๋ณํฉ๋๋ค. ์ฟผ๋ฆฌ ์คํ ๊ณํ์ ์กฐ์ฌํ๊ธฐ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ค์์ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํ ์ ์๋ ๋๊ตฌ๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
`timeit`์ ์ฌ์ฉํ๋ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import timeit
# Setup code (create database, insert data, etc.) - same setup code from previous examples
# Function using ORM
def orm_query():
#ORM query
session = Session()
user = session.query(User).filter_by(name='Alice').first()
session.close()
return user
# Function using Raw SQL
def raw_sql_query():
#Raw SQL query
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute("SELECT name, age FROM users WHERE name = ?", ('Alice',))
user = cursor.fetchone()
conn.close()
return user
# Measure execution time for ORM
orm_time = timeit.timeit(orm_query, number=1000)
# Measure execution time for Raw SQL
raw_sql_time = timeit.timeit(raw_sql_query, number=1000)
print(f"ORM Execution Time: {orm_time}")
print(f"Raw SQL Execution Time: {raw_sql_time}")
์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ผ๋ ค๋ฉด ์ค์ ๋ฐ์ดํฐ ๋ฐ ์ฟผ๋ฆฌ ํจํด์ผ๋ก ๋ฒค์น๋งํฌ๋ฅผ ์คํํ์ญ์์ค.
๊ฒฐ๋ก
Python ORM๊ณผ Raw SQL ์ค์์ ์ ํํ๋ ค๋ฉด ๊ฐ๋ฐ ์์ฐ์ฑ, ์ ์ง ๊ด๋ฆฌ์ฑ ๋ฐ ๋ณด์ ๊ณ ๋ ค ์ฌํญ์ ๋ํ ์ฑ๋ฅ ํธ๋ ์ด๋ ์คํ๋ฅผ ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ORM์ ํธ์์ฑ๊ณผ ์ถ์ํ๋ฅผ ์ ๊ณตํ๋ ๋ฐ๋ฉด, Raw SQL์ ์ธ๋ฐํ ์ ์ด์ ์ ์ฌ์ ์ธ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ฐ ์ ๊ทผ ๋ฐฉ์์ ๊ฐ์ ๊ณผ ์ฝ์ ์ ์ดํดํจ์ผ๋ก์จ ์ ๋ณด์ ์ ๊ฐํ ๊ฒฐ์ ์ ๋ด๋ฆฌ๊ณ ํจ์จ์ ์ด๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ํ์ด๋ธ๋ฆฌ๋ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ ค์ํ์ง ๋ง๊ณ ํญ์ ์ฝ๋๋ฅผ ๋ฒค์น๋งํนํ์ฌ ์ต์ ์ ์ฑ๋ฅ์ ๋ณด์ฅํ์ญ์์ค.
์ถ๊ฐ ํ์
- SQLAlchemy ๋ฌธ์: https://www.sqlalchemy.org/
- Django ORM ๋ฌธ์: https://docs.djangoproject.com/en/4.2/topics/db/models/
- Peewee ORM ๋ฌธ์: http://docs.peewee-orm.com/
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ ํ๋ ๊ฐ์ด๋: (ํน์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ (์: PostgreSQL, MySQL)์ ๋ํ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค)